﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iTunesLib;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using iTunesFastForward.Lyrics;

namespace iTunesFastForward
{
    class TrackEventArgs : EventArgs
    {
        public IITTrack Track { get; set; }
    }

    class COMCallStateEventArgs : EventArgs
    {
        public bool Disabled { get; set; }
    }

    class iTunesActions : IDisposable
    {

        static iTunesActions _instance;

        public static iTunesActions Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new iTunesActions();
                return _instance;
            }
        }

        public IITTrack PlayingTrack {
            get {
                try
                {
                    return app.CurrentTrack;
                }
                catch (Exception)
                {
                    return null;
                }
            }
        }

        public ITPlayerState PlayerState
        {
            get
            {
                return app.PlayerState;
            }
        }

        public int PlayerPosition
        {
            get
            {
                return app.PlayerPosition;
            }
        }

        public delegate void TrackEventHandler(object sender, TrackEventArgs e);
        public delegate void COMCallStateEventHandler(object sender, COMCallStateEventArgs e);

        public event TrackEventHandler TrackPlayedOrChanged;
        public event COMCallStateEventHandler COMCallStateChanged;

        iTunesApp app;
        public bool COMCallDisabled { get; set; }

        /// <summary>
        /// The song rate with stars, 0 to 5
        /// </summary>
        public int SongRate
        {
            get { return app.CurrentTrack.Rating / 20; }
            set { app.CurrentTrack.Rating = value * 20; }
        }

        public int Volume
        {
            get { return app.SoundVolume; }
            set { app.SoundVolume = value; }
        }

        public IITTrack[] SelectedTracks
        {
            get
            {
                if (app.SelectedTracks == null)
                    return null;

                List<IITTrack> tracks = new List<IITTrack>();
                foreach (IITTrack t in app.SelectedTracks)
                    tracks.Add(t);
                return tracks.ToArray();
            }
        }

        public iTunesActions()
        {
            app = new iTunesApp();
            app.OnPlayerPlayEvent += new _IiTunesEvents_OnPlayerPlayEventEventHandler(app_OnPlayerPlayEvent);
            app.OnAboutToPromptUserToQuitEvent += new _IiTunesEvents_OnAboutToPromptUserToQuitEventEventHandler(app_OnAboutToPromptUserToQuitEvent);
            app.OnCOMCallsDisabledEvent += new _IiTunesEvents_OnCOMCallsDisabledEventEventHandler(app_OnCOMCallsDisabledEvent);
            app.OnCOMCallsEnabledEvent += new _IiTunesEvents_OnCOMCallsEnabledEventEventHandler(app_OnCOMCallsEnabledEvent);
        }

        void app_OnCOMCallsEnabledEvent()
        {
            COMCallDisabled = false;
            OnCOMCallStateChanged(false);
        }

        void app_OnCOMCallsDisabledEvent(ITCOMDisabledReason reason)
        {
            COMCallDisabled = true;
            OnCOMCallStateChanged(true);
        }

        void app_OnAboutToPromptUserToQuitEvent()
        {
            // quitter l'application, ca libérera les ressources
            Application.Exit();
        }

        void app_OnPlayerPlayEvent(object iTrack)
        {
            OnTrackChangedOrPlayed((IITTrack)iTrack);
        }

        void OnTrackChangedOrPlayed(IITTrack track)
        {
            if (TrackPlayedOrChanged != null)
                TrackPlayedOrChanged(this, new TrackEventArgs { Track = track });
        }

        void OnCOMCallStateChanged(bool disabled)
        {
            if (COMCallStateChanged != null)
                COMCallStateChanged(this, new COMCallStateEventArgs { Disabled = disabled });
        }

        public string GetITunesFolder()
        {
            string[] parts = app.LibraryXMLPath.Split('\\');
            return string.Join(@"\", parts, 0, parts.Length - 1);
        }

        public List<IITPlaylist> GetPlaylists()
        {
            List<IITPlaylist> playlists = new List<IITPlaylist>();
            foreach (IITSource objSource in app.Sources)
            {
                if (objSource.Kind == ITSourceKind.ITSourceKindLibrary)
                {
                    foreach (IITPlaylist playlist in objSource.Playlists)
                        playlists.Add(playlist);
                }
            }

            return playlists;

        }

        public bool ToggleShuffle()
        {
            app.CurrentPlaylist.Shuffle = !app.CurrentPlaylist.Shuffle;
            return app.CurrentPlaylist.Shuffle;
        }

        public bool ToggleMute()
        {
            app.Mute = !app.Mute;
            return app.Mute;
        }

        public void DoAction(string action)
        {
            // utiliser l'action en string en tant que méthode avec la reflection
            Type t = app.GetType();
            t.GetMethod(action).Invoke(app, null);

        }


        public void SetImage(BackgroundWorker worker, IITTrack track, string filePath, bool applyForAllAlbum)
        {
            if (applyForAllAlbum)
            {
                worker.ReportProgress(5);
                
                List<IITTrack> tracksToChange = new List<IITTrack>();
                foreach (IITTrack t in app.LibraryPlaylist.Tracks)
                {
                    if (t.Album == track.Album && t.Artist == track.Artist)
                        tracksToChange.Add(t);
                }

                worker.ReportProgress(10);

                int i = 0;
                foreach (var t in tracksToChange)
                {
                    SetImageForTrack(filePath, t);
                    worker.ReportProgress((int)((float)i * 90 / tracksToChange.Count) + 10);
                    i++;
                }

            }
            else
            {
                SetImageForTrack(filePath, track);
            }
        }

        private void SetImageForTrack(string filePath, IITTrack t)
        {
            // vider les artworks actuels
            while (t.Artwork.Count != 0)
                t.Artwork[1].Delete();

            // appliquer l'actuel
            t.AddArtworkFromFile(filePath);
        }

        public List<IITFileOrCDTrack> GetSongsWithoutLyrics(LyricsManager manager)
        {
            List<IITFileOrCDTrack> tracks = new List<IITFileOrCDTrack>();
            try
            {
                foreach (IITSource s in app.Sources)
                {
                    if (s.Kind == ITSourceKind.ITSourceKindLibrary)
                    {
                        foreach (IITPlaylist p in s.Playlists)
	                    {
                            if (p.Name == "Music")
                            {
                                foreach (IITTrack t in app.LibraryPlaylist.Tracks)
                                {
                                    // enlever les types de fichiers qui ne supportent pas les lyrics et tout ce qui n'est pas fichier
                                    if (t.Kind == ITTrackKind.ITTrackKindFile)
                                    {
                                        IITFileOrCDTrack tr = (IITFileOrCDTrack)t;

                                        try
                                        {
                                            if (!manager.LyricsExist(tr))
                                                tracks.Add(tr);
                                        }
                                        catch (COMException)
                                        {
                                            continue;
                                        }
                                    }
                                }
                                break;
                            }
                    		 
	                    }

                        break;
                    }
                }
                {
                    
                }
            }
            catch (COMException)
            {
                return null;
            }

            return tracks;
        }


        public void DeleteAllLyrics(LyricsManager l)
        {
            int i = 0;
            foreach (IITTrack t in app.LibraryPlaylist.Tracks)
            {
                l.RemoveLyrics(t);
                i++;
            }

        }

        /// <summary>
        /// Creates a playlist with the specified name or returns the existing one.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public IITUserPlaylist CreatePlaylist(string name)
        {
            IITUserPlaylist pl = null;
            foreach (IITSource s in app.Sources)
            {
                if (s.Kind == ITSourceKind.ITSourceKindLibrary)
                {
                    foreach (IITPlaylist p in s.Playlists)
                    {
                        if (p.Name == name)
                        {
                            pl = (IITUserPlaylist)p;
                            break;
                        }
                    }
                    break;
                }
            }

            if (pl == null)
                pl = (IITUserPlaylist)app.CreatePlaylist(name);

            return pl;
        }

        /// <summary>
        /// Clears a playlist from all its tracks
        /// </summary>
        /// <param name="pl"></param>
        public void ClearPlaylist(IITPlaylist pl)
        {
            int c = pl.Tracks.Count;
            for (int i = 0; i < c; i++)
                pl.Tracks[1].Delete();
        }

        public IITTrack GetTrackFromTrackDatabaseID(int s, int p, int t, int d)
        {
            return (IITTrack) app.GetITObjectByID(s, p, t, d);
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (!COMCallDisabled)
            {
                app.OnPlayerPlayEvent -= new _IiTunesEvents_OnPlayerPlayEventEventHandler(app_OnPlayerPlayEvent);
                app.OnAboutToPromptUserToQuitEvent -= new _IiTunesEvents_OnAboutToPromptUserToQuitEventEventHandler(app_OnAboutToPromptUserToQuitEvent);

                Marshal.ReleaseComObject(app);
                app = null;
                GC.Collect();
            }
        }

        #endregion
    }
}
